from Util.Return import *
from Util.Process import *
from Data.DataStorage import *
from Util.SQL import *
from terracatalogueclient import Catalogue
from shapely.geometry import Polygon, Point
import shutil
from PIL import Image


class TerrascopeAPI:
    # https://vitobelgium.github.io/terracatalogueclient/api.html
    def __init__(self):
        self.name = get_config("data", "Terrascope")['name']
        self.collections = get_config("data", "Terrascope")['collections']
        self.attribute = get_config("data", "Terrascope")['attribute']
        self.download_path = get_path(os.path.abspath(__file__), 4, get_config("data", "Terrascope")['download_path'])
        self.available_path = get_path(os.path.abspath(__file__), 4, get_config("data", "Terrascope")['available_path'])
        self.quicklook_path = get_path(os.path.abspath(__file__), 4, get_config("data", "Terrascope")['quicklook_path'])
        self.username = get_config("config", "terrascope_api_key")['username']
        self.password = get_config("config", "terrascope_api_key")['password']
        self.catalogue = Catalogue().authenticate_non_interactive(self.username, self.password)

    def search(self, search_params):  # 通过API查询数据
        scenes = self.catalogue.get_products(**search_params)
        scenes_len = self.catalogue.get_product_count(**search_params)

        INFO("INFO", f'Terrascope API: Found {scenes_len} scenes found')
        return scenes

    def download(self, scenes):  # 通过API下载数据
        for scene_id in scenes:
            collection_id = self.attribute[scene_id.rsplit("_", 1)[0]]['collection']
            product_id = scene_id
            INFO("INFO", f'Terrascope API: Start Download {scene_id}')
            try:
                product = self.catalogue.get_products(collection=collection_id, title=product_id)
                self.catalogue.download_products(products=product, path=self.download_path, force=True)
            except Exception as e:
                INFO("ERROR", f'Terrascope API: Download ERROR {scene_id}: {e}')
            INFO("INFO", f'Terrascope API: Success Download {scene_id}')

    def preprocess(self, scenes):  # 处理文件转为标准的TIFF和QUICKLOOK
        success = []
        for scene_id in scenes:
            INFO("INFO", f'Terrascope API: Start Preprocess {scene_id}')
            collection_id = scene_id.rsplit("_", 1)[0]
            product_id = scene_id
            download_data_name = None
            try:
                if collection_id in ['ESA_WorldCover_10m_2020_V100', 'ESA_WorldCover_10m_2021_v200']:
                    download_data_name = product_id + "_Map.tif"
                if os.path.exists(os.path.join(self.download_path, product_id)):  # 判断是否存在
                    download_data = os.path.join(os.path.join(self.download_path, product_id), download_data_name)
                    shutil.move(download_data, self.available_path)
                    shutil.rmtree(os.path.join(self.download_path, product_id))
                    os.rename(os.path.join(self.available_path, download_data_name),
                              os.path.join(self.available_path, product_id + '.TIFF'))
                    # 生成quick_look
                    image = Image.open(os.path.join(self.available_path, scene_id + '.TIFF'))
                    image = image.resize((1024, 1024))  # 调整图像大小为缩略图尺寸
                    image.save(os.path.join(self.quicklook_path, scene_id + '.png'), "PNG")  # 将图像保存为PNG格式
                success.append(True)
                INFO("INFO", f'Terrascope API: Success Preprocess {scene_id}')
            except Exception as e:
                INFO("ERROR", f'Terrascope API: Preprocess ERROR {scene_id}: {e}')
                success.append(False)
        return success

    def upload(self, scenes):
        for scene_id in scenes:
            INFO("INFO", f"Terrascope API: Start Upload {scene_id}")
            available_data = os.path.join(self.available_path, scene_id + ".TIFF")
            quicklook_data = os.path.join(self.quicklook_path, scene_id + ".png")
            local_data_list = [available_data, quicklook_data]
            hdfs_path_list = ["/" + get_config("data", "Terrascope")['available_path'],
                              "/" + get_config("data", "Terrascope")['quicklook_path']]
            hdfs = HDFS()  # 创建一个HDFS连接
            Flag = True
            for index in range(len(local_data_list)):  # 上传
                hdfs.push(hdfs_path_list[index], local_data_list[index])
                if os.path.basename(local_data_list[index]) != scene_id + ".png":  # 不删除quicklook
                    os.remove(local_data_list[index])  # 删除文件
                    continue  # 处理特殊情况、不存在quick_look
                if not hdfs.exist(hdfs_path_list[index] + "/" + os.path.basename(local_data_list[index])):
                    Flag = False
            if Flag:
                update({"available": 1}, f'scene_id = "{scene_id}"', 'data')  # 更新数据为可用状态
                INFO("INFO", f"Terrascope API: {scene_id} data is available!")
            else:
                INFO("INFO", f"Terrascope API: {scene_id} data is not available!")

    def request(self, date, bbox=None, point=None):  # 请求且更新数据 bbox是一个元组
        datasets = self.collections
        result_list = []
        for dataset in datasets:
            if point is None:
                search_params = {
                    'collection': dataset,
                    'geometry': Polygon.from_bounds(*bbox),
                    'start': date[0],
                    'end': date[1]
                }
            else:
                search_params = {
                    'collection': dataset,
                    'geometry': Point([point['lng'], point['lat']]),
                    'start': date[0],
                    'end': date[1]
                }
            scenes = self.search(search_params)
            result_list = result_list + self.resolve(scenes)
        return result_list

    def resolve(self, scenes):  # 解析API返回的查询结果返回为数据库内的格式
        # 对原始json序列进行处理
        result = []
        for scene in scenes:
            collection_tag = scene.id.rsplit(":", 1)[1].rsplit("_", 1)[0]
            scene_coords = list(scene.geometry.exterior.coords)
            #####################
            result_json = {
                'dataset': self.name,
                'scene_id': scene.id.rsplit(":", 1)[1],
                'data_id': get_data_id(),
                'type': self.attribute[collection_tag]['datatype'],
                'product': self.attribute[collection_tag]['processingLevel'],
                'satellite': self.attribute[collection_tag]['satellite'],
                'date': scene.beginningDateTime.strftime("%Y-%m-%d"),
                'address': get_address([scene_coords[0], scene_coords[3], scene_coords[1], scene_coords[2]]),
                'bbox': (scene.bbox[0], scene.bbox[1], scene.bbox[2], scene.bbox[3]),
                'cbox': (scene_coords[0], scene_coords[3], scene_coords[1], scene_coords[2]),
                'available': 0,
                'json': scene.properties
            }
            result.append(result_json)
        return result